package com.qyer.commons.service.resources;

import static com.qyer.commons.http.ErrorHttpResult.createErrorResult;
import static com.qyer.commons.http.NormalHttpResult.createEmptyNormalResult;
import static com.qyer.commons.http.NormalHttpResult.createNormalResult;
import static com.qyer.commons.service.conf.CommonsMetaInfo.NAMESPACE;
import static com.qyer.commons.service.conf.CommonsMetaInfo.SERVICE_NAME;
import static com.qyer.commons.utils.CommonUtils.getRequestId;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;

import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Optional;
import com.qyer.commons.http.HttpResult;
import com.qyer.commons.mc.MutableCache;
import com.qyer.commons.place.City;
import com.qyer.commons.place.Country;
import com.qyer.commons.place.Province;
import com.qyer.commons.place.QyerPlace;
import com.qyer.commons.service.model.PlaceDict;
import org.apache.commons.collections4.CollectionUtils;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import java.util.List;
import java.util.Map;

/**
 * User: Z J Wu Date: 2016/03/07 Time: 20:13 Package: com.qyer.commons.service.resources
 */
@Path("/place")
@Produces(APPLICATION_JSON + "; charset=utf-8;")
public class PlaceResource {

  private MutableCache<PlaceDict<Integer, Country>> countryPlaceDictMC;
  private MutableCache<PlaceDict<Integer, City>> cityPlaceDictMC;
  private MutableCache<PlaceDict<Integer, City>> chinaCityPlaceDictMC;

  private MutableCache<Map<Integer, Country>> countryDictMC;
  private MutableCache<Map<Integer, City>> cityDictMC;

  private MutableCache<List<Province>> provincesOfChinaMC;

  public PlaceResource(MutableCache<PlaceDict<Integer, Country>> countryPlaceDictMC,
                       MutableCache<PlaceDict<Integer, City>> cityPlaceDictMC,
                       MutableCache<PlaceDict<Integer, City>> chinaCityPlaceDictMC,
                       MutableCache<Map<Integer, Country>> countryDictMC,
                       MutableCache<Map<Integer, City>> cityDictMC,
                       MutableCache<List<Province>> provincesOfChinaMC) {
    this.countryPlaceDictMC = countryPlaceDictMC;
    this.cityPlaceDictMC = cityPlaceDictMC;
    this.countryDictMC = countryDictMC;
    this.cityDictMC = cityDictMC;
    this.chinaCityPlaceDictMC = chinaCityPlaceDictMC;
    this.provincesOfChinaMC = provincesOfChinaMC;
  }

  public PlaceResource() {
  }

  public HttpResult generateErrorIfInvalid(long t1, Optional<String> context, int id) {
    if (!context.isPresent()) {
      return createErrorResult(SERVICE_NAME, NAMESPACE, getRequestId(),
                               System.currentTimeMillis() - t1, 261100, "context is null");
    }
    if (id == 0) {
      return createErrorResult(SERVICE_NAME, NAMESPACE, getRequestId(),
                               System.currentTimeMillis() - t1, 261100, "Invalid id.");
    }
    return null;
  }

  public HttpResult generateErrorIfInvalid(long t1, Optional<String> context) {
    if (!context.isPresent()) {
      return createErrorResult(SERVICE_NAME, NAMESPACE, getRequestId(),
                               System.currentTimeMillis() - t1, 261100, "context is null");
    }
    return null;
  }

  private <QP extends QyerPlace> HttpResult loadQyerPlacesByPlaceDict(
    MutableCache<PlaceDict<Integer, QP>> dict, int parentId, long beginTime) {
    List<QP> qyerPlace = dict.getCacheContent().get(parentId);
    if (CollectionUtils.isEmpty(qyerPlace)) {
      return createEmptyNormalResult(SERVICE_NAME, NAMESPACE, getRequestId(),
                                     System.currentTimeMillis() - beginTime);
    }
    return createNormalResult(SERVICE_NAME, NAMESPACE, getRequestId(), "DATA-IN-CATEGORY",
                              System.currentTimeMillis() - beginTime, qyerPlace);
  }

  private <QP extends QyerPlace> HttpResult loadQyerPlaceById(MutableCache<Map<Integer, QP>> dict,
                                                              int id, long beginTime) {
    QP qyerPlace = dict.getCacheContent().get(id);
    if (qyerPlace == null) {
      return createEmptyNormalResult(SERVICE_NAME, NAMESPACE, getRequestId(),
                                     System.currentTimeMillis() - beginTime);
    }
    return createNormalResult(SERVICE_NAME, NAMESPACE, getRequestId(), "DATA-IN-CATEGORY",
                              System.currentTimeMillis() - beginTime, qyerPlace);
  }

  @GET
  @Timed
  @Path("/continent/{continentId}/countries")
  public HttpResult getCountriesByContinentId(@QueryParam("context") Optional<String> context,
                                              @PathParam("continentId") int continentId) {
    long t1 = System.currentTimeMillis();
    HttpResult result = generateErrorIfInvalid(t1, context, continentId);
    return result != null ? result : loadQyerPlacesByPlaceDict(countryPlaceDictMC, continentId, t1);
  }

  @GET
  @Timed
  @Path("/country/{countryId}/cities")
  public HttpResult getCitiesByCountryId(@QueryParam("context") Optional<String> context,
                                         @PathParam("countryId") int countryId) {
    long t1 = System.currentTimeMillis();
    HttpResult result = generateErrorIfInvalid(t1, context, countryId);
    return result != null ? result : loadQyerPlacesByPlaceDict(cityPlaceDictMC, countryId, t1);
  }

  @GET
  @Timed
  @Path("/china/province/{provinceId}/cities")
  public HttpResult getCitiesOfOneChinaByProvinceId(@QueryParam("context") Optional<String> context,
                                                    @PathParam("provinceId") int provinceId) {
    long t1 = System.currentTimeMillis();
    HttpResult result = generateErrorIfInvalid(t1, context, provinceId);
    return result != null ? result
                          : loadQyerPlacesByPlaceDict(chinaCityPlaceDictMC, provinceId, t1);
  }

  @GET
  @Timed
  @Path("/country/{countryId}")
  public HttpResult getCountryInfo(@QueryParam("context") Optional<String> context,
                                   @PathParam("countryId") int countryId) {
    long t1 = System.currentTimeMillis();
    HttpResult result = generateErrorIfInvalid(t1, context, countryId);
    return result == null ? loadQyerPlaceById(countryDictMC, countryId, t1) : result;
  }

  @GET
  @Timed
  @Path("/city/{cityId}")
  public HttpResult getCityInfo(@QueryParam("context") Optional<String> context,
                                @PathParam("cityId") int cityId) {
    long t1 = System.currentTimeMillis();
    HttpResult result = generateErrorIfInvalid(t1, context, cityId);
    return result == null ? loadQyerPlaceById(cityDictMC, cityId, t1) : result;
  }

  @GET
  @Timed
  @Path("/china/province")
  public HttpResult getProvincesOfChina(@QueryParam("context") Optional<String> context) {
    long t1 = System.currentTimeMillis();
    HttpResult result = generateErrorIfInvalid(t1, context);
    if (result != null) {
      return result;
    }
    List<Province> provinces = provincesOfChinaMC.getCacheContent();
    if (CollectionUtils.isEmpty(provinces)) {
      return createEmptyNormalResult(SERVICE_NAME, NAMESPACE, getRequestId(),
                                     System.currentTimeMillis() - t1);
    }
    result = createNormalResult(SERVICE_NAME, NAMESPACE, getRequestId(), "DATA-IN-CATEGORY",
                                System.currentTimeMillis() - t1, provinces);
    return result;
  }

}
